
#ifndef _GSKELMESH_ANIMATOR_H_
#define _GSKELMESH_ANIMATOR_H_

#include "mesh.h"
#include "ganimator.h"

class GMeshAnimator: public GAnimator {
   
public:
   GMeshAnimator() {
      mesh = 0;
   }
   
   GMeshAnimator(const GMeshAnimator& anim) 
      : GAnimator(anim.gskeleton, anim.skeleton, anim.motion) {
      mesh = anim.mesh;
      setting();
   }
   
   GMeshAnimator(Mesh *m, GSkeleton *gs, Skeleton *s, Motion *mo)
      : GAnimator(gs, s, mo) {
      mesh = m;
      setting();
   }
   
   void frame(int f) {
      
      GAnimator::frame(f);
      
      gskeleton->convert2DualQuat();
      
      int i = 0;
      Vertex_iterator vi = mesh->vertices_begin();
      while (vi != mesh->vertices_end()) {
         ///
         Number sumw = 0.0;
         OMR::Quaternion<> qq(0,0,0,0), dqq(0,0,0,0);
         for (int j=0; j<vi->weights.size(); ++j) {
            const Number &w = vi->weights[j];
            if (w == 0) continue;
            OMR::Quaternion<> q = gskeleton->getQuatPart(j);
            OMR::Quaternion<> dq = gskeleton->getDualPart(j);
            
            Number dot = qq[0]*q[0] + qq[1]*q[1] + qq[2]*q[2] + qq[3]*q[3];
            if (dot < 0) {
               q = q*(-1.0);
               dq = dq*(-1.0);
            }
            
            dqq = dqq + dq*w;
            qq = qq + q*w;
            //~ sumw += w;
         }
         
         Quat QQ(qq[0],qq[1],qq[2],qq[3]);
         Quat DQQ(dqq[0],dqq[1],dqq[2],dqq[3]);
         
         //~ QQ = QQ*(1.0/sumw);
         //~ DQQ = DQQ*(1.0/sumw);
         
         Number normaQQ = length(QQ);
         Quat Q = QQ*(1.0/normaQQ);
         DQQ = DQQ*(1.0/normaQQ);
         
         Quat tQQ = DQQ*conjugate(Q);
         Vector3 tv(tQQ[1],tQQ[2],tQQ[3]);
         
         const Point3 &Po = ipositions[i]; // the original vertex position
         Quat qPo(Po[0],Po[1],Po[2]);
         Quat qp = Q*qPo*conjugate(Q);
         Point3 &P = vi->point();
         P = Point3(qp[1],qp[2],qp[3]) + tv; // the deformed vertex position
         
         const Vector3 &No = inormals[i]; // the original vertex normal
         Quat qNo(No[0],No[1],No[2]);
         Quat qn = Q*qNo*conjugate(Q);
         Vector3 &N = vi->normal();
         N = Vector3(qn[1],qn[2],qn[3]); // the deformed vertex normal
         
         /// 
         //~ OMR::Transform<> T;
         //~ for (int j=0; j<vi->weights.size(); ++j) {
            //~ const Number &w = vi->weights[j];
            //~ if (w == 0) continue;
            //~ T = T + gskeleton->transformation[j]*w;
         //~ }
         //~ const Point3 &Po = ipositions[i]; // the original vertex position
         //~ OMR::Vector3 p(Po[0], Po[1], Po[2]);
         //~ p = T*p;
         //~ Point3 &P = vi->point();
         //~ P = Point3(p[0],p[1],p[2]); // the deformed vertex position
         
         ++vi; ++i;
      }
   }
   
protected:
   void setting() {
      
      ipositions.resize(mesh->nvertices());
      inormals.resize(mesh->nvertices());
      Vertex_iterator vi = mesh->vertices_begin();
      for (unsigned int i=0; i<ipositions.size(); ++i, ++vi) {
         ipositions[i] = vi->point();
         inormals[i] = vi->normal();
      }
   }
   
protected:
   
   Mesh                       *mesh;
   vector<Point3>             ipositions; // initial vertex positions
   vector<Vector3>            inormals; // initial vertex normal
};

#endif
